home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 November: Tool Chest / Dev.CD Nov 98 TC.toast / Sample Code / Snippets / QuickDraw / Custom PicComments⁄Bottlenecks / Source / CustomPC⁄B.c
Encoding:
Text File  |  1997-03-20  |  20.4 KB  |  671 lines  |  [TEXT/CWIE]

  1. /*
  2. **  Apple Macintosh Developer Technical Support
  3. **
  4. **  Sample showing how to implement custom PicComments and QuickDraw bottlenecks. 
  5. **    See the ReadMe for code details.
  6. **
  7. **  revised by Ingrid Kelly, Apple Developer Technical Support
  8. **
  9. **  File:   CustomPCB.c
  10. **
  11. **  Copyright © 1991-1997 Apple Computer, Inc.
  12. **  All rights reserved.
  13. **
  14. **    10/91    v. 1.0    dh    Shipped as 'DTS Groupies' sample.
  15. **    03/97    v. 2.0    ik    Rewritten as 'Custom PicComments/Bottlenecks'
  16. **
  17. **  You may incorporate this sample code into your applications without
  18. **  restriction, though the sample code has been provided "AS IS" and the
  19. **  responsibility for its operation is 100% yours.  However, what you are
  20. **  not permitted to do is to redistribute the source as "Apple Sample
  21. **  Code" after having made changes. If you're going to re-distribute the
  22. **  source, we require that you make it clear in the source that the code
  23. **  was descended from Apple Sample Code, but that you've made changes.
  24. */
  25.  
  26. #include <Dialogs.h>
  27. #include <Fonts.h>
  28. #include <Menus.h>
  29. #include <Devices.h>
  30. #include <Resources.h>
  31.  
  32. /*------ constants --------------------------------------------------------------------------*/
  33.  
  34.  
  35. #define kCreatorType    'EGAD'        /* Our creator type.                */
  36.  
  37. #define rMenuBar        128            /* The menubar resource ID.            */
  38. #define mApple            128            /* Apple menu ID.                    */
  39. #define iAbout            1            /* "About…" menu item index.        */
  40. #define mFile            129            /* File menu ID.                    */
  41. #define iQuit            1            /* Quit menu item index.            */
  42.  
  43. #define kMaxPICTs        50            /* Max. no. of pictures we handle.    */
  44. #define kCustomComment    100            /* Custom PicComment indicator.        */
  45. #define kSubPICTComment    200            /* Our (sub-picture) sub-PicComment.
  46.                                        This comment indicates that we've
  47.                                        stored a picture inside of a
  48.                                        picture.  We use it to extract
  49.                                        the individual PICTs.            */
  50.  
  51. /*------ types --------------------------------------------------------------------------*/
  52.  
  53.  
  54. typedef struct TPICTRec {
  55.     int            numPICTs;            /* The number of sub-pictures,         */
  56.     PicHandle    picture[kMaxPICTs];    /* and their PicHandles,            */
  57.     Rect        curPos[kMaxPICTs];    /* and their last drawn positions.    */
  58. } TPICTRec;
  59.  
  60. /*------ globals --------------------------------------------------------------------------*/
  61.  
  62.  
  63. static TPICTRec        gPICTRec;        /* Our global picture record.        */
  64. static Rect            gPictsBounds;    /* The bounds used by our pictures.    */
  65. static Boolean        gQuitting;        /* "Quitting?" flag.                */
  66. static WindowPtr    gTheWindow;        /* Our window's pointer.            */
  67.  
  68.  
  69. /*------ prototypes ------------------------------------------------------------------------*/
  70.  
  71. extern void            CompositePictures(void);
  72. extern pascal void    CustomPicProc(int kind, int dataSize, Handle dataHandle);
  73. extern void            DisassemblePictures(void);
  74. extern void            DoMenuCommand(long menuResult);
  75. extern void            EventLoop(void);
  76. extern void            MoveThePicts(Rect *wBounds);
  77. extern void            MakeThePicts(void);
  78. extern void            ShowThePicts(void);
  79.  
  80.  
  81.  
  82. /*------ CompositePictures ----------------------------------------------------------------*/
  83. //    CompositePictures groups all of the pictures in the global picture record
  84. //    into one "composite" picture.  It removes all of the old pictures and
  85. //    stores the new one.
  86. /*----------------------------------------------------------------------------------------*/
  87.  
  88. void CompositePictures()
  89. {
  90.     PicHandle    aPICT, groupPICT;
  91.     RgnHandle    oldClip;
  92.     int            idx;
  93.     long        dataSize;
  94.     long        ownerApp;
  95.     short        localPicComment;
  96.  
  97. /*    Save the old clipping region, and set a valid one so our grouped
  98.     picture develops ok.                                                */
  99.  
  100.     oldClip = NewRgn();
  101.     GetClip(oldClip);
  102.     ClipRect(&gPictsBounds);
  103.  
  104.     groupPICT = OpenPicture(&gPictsBounds);
  105.  
  106.  
  107. /*    Create a picture to contain all the other ones, then draw those into
  108.     it, separated by our PicComments.  Kill the individual pictures as
  109.     we go.  Finally, close the composite picture.                        */
  110.  
  111.     ownerApp = kCreatorType;
  112.     localPicComment = kSubPICTComment;
  113.  
  114.     for(idx = 0; idx < gPICTRec.numPICTs; idx++)
  115.     {
  116.         aPICT = gPICTRec.picture[idx];
  117.  
  118.  
  119. /*    We don't just use a single custom PicComment since another app may
  120.     use the same comment and conflicts could result.  (Not in this app,
  121.     but in the real world.)  We add six bytes to the handle and store the
  122.     creator type of the app that made the picture followed by 2 bytes
  123.     for a local PicComment kind within the app.  If we used more than
  124.     one PicComment in this app, this extra information would be
  125.     necessary.                                                            */
  126.  
  127.         dataSize = GetHandleSize((Handle) aPICT) +6;
  128.         SetHandleSize((Handle) aPICT, dataSize);
  129.  
  130.         BlockMove((Ptr) *aPICT, (Ptr) *aPICT +6, dataSize -6);
  131.         BlockMove(&ownerApp, (Ptr) *aPICT, 4);
  132.         BlockMove(&localPicComment, (Ptr) *aPICT +4, 2);
  133.  
  134.         PicComment(kCustomComment, dataSize, (Handle) aPICT);
  135.  
  136. /*    Fix the original PicHandle so that we can draw our picture for apps
  137.     that don't know about our custom comments.                            */
  138.  
  139.         BlockMove((Ptr) *aPICT +6, (Ptr) *aPICT, dataSize -6);
  140.         SetHandleSize((Handle) aPICT, dataSize -6);
  141.         DrawPicture(aPICT, &(*aPICT)->picFrame);
  142.         KillPicture(aPICT);
  143.         gPICTRec.picture[idx] = NULL;
  144.     }
  145.  
  146.     ClosePicture();
  147.  
  148.  
  149. /*    Restore the original clipping region and update our global picture
  150.     record so that we have one consolidated picture, in the first slot.
  151.     We set it's current position to (0, 0, 0, 0) so that we don't waste
  152.     time erasing anything on the first draw.                            */
  153.  
  154.     SetClip(oldClip);
  155.     DisposeRgn(oldClip);
  156.  
  157.     gPICTRec.numPICTs = 1;
  158.     gPICTRec.picture[0] = groupPICT;
  159.     SetRect(&gPICTRec.curPos[0], 0, 0, 0, 0);
  160. }
  161.  
  162.  
  163. /*------ CustomPicProc ----------------------------------------------------------------*/
  164. //        CustomPicProc is our replacement for the port's StdCommentProc.
  165. //         in the global picture record
  166. /*----------------------------------------------------------------------------------------*/
  167.  
  168. pascal void CustomPicProc(int kind, int dataSize, Handle dataHandle)
  169. {
  170.     int            nextNum;
  171.     long        ownerApp;
  172.     short        localPicComment;
  173.     Handle        theHandle;
  174.  
  175. /*    If this is a custom PicComment, see if it's ours.  In this app,
  176.     we know it always will be, but when you import other pictures
  177.     you can't be so sure.                                                */
  178.  
  179.     if (kind == kCustomComment && (gPICTRec.numPICTs < kMaxPICTs))
  180.     {
  181.         if (dataSize < 6) return;                        /* Not ours?    */
  182.         
  183.         BlockMove((Ptr) *dataHandle, &ownerApp, 4);
  184.         BlockMove((Ptr) *dataHandle +4, &localPicComment, 2);
  185.  
  186.         if ((ownerApp != kCreatorType) ||                /* Not ours?    */
  187.             (localPicComment != kSubPICTComment)) return;
  188.  
  189.  
  190. /*    This is indeed our picture comment.  Create a handle for the data we
  191.     found, store it in our global picture record and bump the number of
  192.     pictures we have.  The reason that we clear the picture's curPos
  193.     rect is so that we won't waste time erasing anything the first time
  194.     we enter MoveTheGroupies.                                            */
  195.  
  196.         nextNum = gPICTRec.numPICTs;
  197.         gPICTRec.picture[nextNum] = (PicHandle) dataHandle;
  198.         SetRect(&gPICTRec.curPos[nextNum], 0, 0, 0, 0);
  199.  
  200.  
  201. /*    After we create the handle for the data, we have to remember that
  202.     we have 6 bytes of identifying "garbage" in front of the picture
  203.     data.  To remove that, BlockMove all the picture data to the
  204.     beginning of the handle and reset the handle's size.  This is kind
  205.     of a hassle, but it's really best to store your custom PicComments
  206.     this way.  Otherwise, you may misinterpret someone elses comments
  207.     or cause them to misinterpret yours.                                */
  208.  
  209.         if (HandToHand((Handle *) &gPICTRec.picture[nextNum]) == noErr)
  210.         {
  211.             ++gPICTRec.numPICTs;
  212.             theHandle = (Handle) gPICTRec.picture[nextNum];
  213.             BlockMove((Ptr) *theHandle +6, (Ptr) *theHandle, dataSize -6);
  214.             SetHandleSize(theHandle, dataSize -6);
  215.         }
  216.     }
  217. }
  218.  
  219.  
  220. /*------ DisassemblePictures ----------------------------------------------------------------*/
  221. //    DisassemblePictures ungroups the first picture in the global picture
  222. //    record.  It replaces that picture with new pictures of every picture
  223. //    it contained.  All drawing is done within another "dummy" picture
  224. //    so that nothing draws on the screen. The reason we can't use an empty
  225. //    clipping region to do this is that PicComments will be clipped out along
  226. //    with everything else, and we'd be hosed.  (We need the PicComments!)
  227.     
  228. //    This code is written so that it installs the GrafProcs correctly for
  229. //    both GrafPorts and CGrafPorts.
  230. /*----------------------------------------------------------------------------------------*/
  231.  
  232. void DisassemblePictures()
  233. {
  234.     GrafPtr        curPort;
  235.     QDProcs        theQDProcs;        /* If we're using a GrafPort…            */
  236.     CQDProcs    theCQDProcs;    /* If we're using a CGrafPort…            */
  237.     PicHandle    dummyPICT;
  238.  
  239. /*    Reset the number of pictures in our global picture record to zero.
  240.     There's actually one picture there at this point (the composite
  241.     one), but we must set this to zero so that our PicComment handler
  242.     stores extracted pictures in the right place.                        */
  243.  
  244.     gPICTRec.numPICTs = 0;
  245.  
  246.  
  247. /*    Get the current port and the standard QDProcs or CQDProcs,
  248.     depending on whether we have a GrafPort or CGrafPort.                */
  249.  
  250.     GetPort(&curPort);
  251.  
  252.     if (curPort->portBits.rowBytes < 0)                /* CGrafPort…        */
  253.     {
  254.         SetStdCProcs(&theCQDProcs);
  255.         theCQDProcs.commentProc = NewQDCommentProc(CustomPicProc);
  256.         curPort->grafProcs = (QDProcsPtr) &theCQDProcs;
  257.     }
  258.     else                                            /* GrafPort…        */
  259.     {
  260.         SetStdProcs(&theQDProcs);
  261.         theQDProcs.commentProc = NewQDCommentProc(CustomPicProc);
  262.         curPort->grafProcs = (QDProcsPtr) &theQDProcs;
  263.     }
  264.  
  265.  
  266. /*    Open our dummy picture and draw into it so that our PicComment
  267.     handler is called to parse the picture.  When finished, close the
  268.     picture, kill it and remove our grafProcs.                            */
  269.  
  270.     dummyPICT = OpenPicture(&(*gPICTRec.picture[0])->picFrame);
  271.     DrawPicture(gPICTRec.picture[0], &(*gPICTRec.picture[0])->picFrame);
  272.     ClosePicture();
  273.     KillPicture(dummyPICT);
  274.  
  275.     curPort->grafProcs = NULL;
  276. }
  277.  
  278.  
  279. /*------ DoMenuCommand ----------------------------------------------------------------*/
  280. //        DoMenuCommand handles our menu items.
  281. /*----------------------------------------------------------------------------------------*/
  282.  
  283. void DoMenuCommand(long menuResult)
  284. {
  285.     int            menuID, menuItem;
  286.     Str255        daName;
  287.     /*MenuHandle    theMenu;*/
  288.     GrafPtr        savePort;
  289.  
  290. /*    Get the menu ID and item ID.            */
  291.  
  292.     menuID = (menuResult >>16) & 0xFFFF;
  293.     menuItem = menuResult & 0xFFFF;
  294.  
  295.  
  296. /*    Do what we're supposed to.                */
  297.  
  298.     switch (menuID)
  299.     {
  300.         case mApple:                        /*    Apple Menu                    */
  301.             switch (menuItem)
  302.             {
  303.                 case iAbout:                /*    -> Handle "About…"            */
  304.                     break;
  305.  
  306.                 default:                    /*    -> The rest are DAs.        */
  307.  
  308.                     GetPort(&savePort);
  309.                     GetMenuItemText(GetMenuHandle(mApple), menuItem, daName);
  310.                     OpenDeskAcc((ConstStr255Param)daName);
  311.                     SetPort(savePort);
  312.                     break;
  313.             };
  314.  
  315.         case mFile:                            /*    File Menu                    */
  316.             switch (menuItem)
  317.             {
  318.                 case iQuit:
  319.                     gQuitting = true;        /*    -> Quit                        */
  320.                     break;
  321.             }
  322.  
  323.     }
  324.  
  325.     HiliteMenu(0);
  326.  
  327. }
  328.  
  329.  
  330. /*------ EventLoop ----------------------------------------------------------------*/
  331. //        EventLoop is a main event loop.  It calls WaitNextEvent and
  332. //        other nice stuff.  It also makes our pictures assemble, disassemble, 
  333. //        and move about.
  334. /*----------------------------------------------------------------------------------------*/
  335.  
  336. void EventLoop()
  337. {
  338.     EventRecord        theEvent;
  339.     WindowPtr        whichWindow;
  340.     short            partCode;
  341.     Rect            dragRect;
  342.     RgnHandle        grayRgn;
  343.     char            key, time;
  344.     long            finalTicks;
  345.  
  346.  
  347. /*    Set up the rectangle for where we can drag windows.  Initialize
  348.     our "time-through-the-loop" counter to -1 so that it gets bumped
  349.     to zero on the first pass.  This will enable us assemble the
  350.     grouped picture as we go through the first time.                        */
  351.  
  352.     grayRgn = GetGrayRgn();
  353.     dragRect = (*grayRgn)->rgnBBox;
  354.     time = -1;
  355.  
  356.  
  357. /*    We have a counter which goes from 0-26 and is incremented each time
  358.     we go through this code. At time = 0, We assemble the grouped image.
  359.     At time = 12, we break all the PICTs out of it.  At time = 27, we
  360.     cycle back to time = 0.  In between these life altering times,
  361.     (at least for groupies), we draw all of our current pictures in
  362.     random places.  This clearly shows whether the PICTs are currently
  363.     grouped or not.  We go through this loop until the user quits.            */
  364.  
  365.     do
  366.     {
  367.         SetPort(gTheWindow);
  368.         time = ++time % 27;
  369.     
  370.          if (time == 0)
  371.         {
  372.             CompositePictures();            /*    Group the pictures.                */
  373.             EraseRect(&(gTheWindow)->portRect);
  374.         }
  375.  
  376.          if (time == 12)
  377.         {
  378.             DisassemblePictures();        /*    Ungroup the pictures.            */
  379.             EraseRect(&(gTheWindow)->portRect);
  380.         }
  381.  
  382.  
  383. /*    Move all pictures so we can see their current state.                    */
  384.  
  385.         MoveThePicts(&(gTheWindow)->portRect);
  386.  
  387.  
  388. /*    Delay so our graphics don't flash.                                        */
  389.  
  390.         Delay((time < 12)? 40:10, &finalTicks);
  391.     
  392.  
  393. /*    Handle any pending events.                                                */
  394.  
  395.         if (WaitNextEvent(everyEvent, &theEvent, 0, NULL))
  396.             switch (theEvent.what)
  397.             {
  398.                 case mouseDown:                    /*    Handle mouse clicks.    */
  399.                 
  400.                     partCode = FindWindow(theEvent.where, &whichWindow);
  401.  
  402.                     switch (partCode)
  403.                     {
  404.                         case inContent:
  405.                             if (whichWindow != FrontWindow())
  406.                                 SelectWindow(whichWindow);
  407.                             break;
  408.     
  409.                         case inDrag:
  410.                             DragWindow(whichWindow, theEvent.where, &dragRect);
  411.                             break;
  412.     
  413.                         case inMenuBar:
  414.                             DoMenuCommand(MenuSelect(theEvent.where));
  415.     
  416.                         case inSysWindow:
  417.                             SystemClick(&theEvent, whichWindow);
  418.                             break;
  419.                     }
  420.                     break;
  421.     
  422.                 case updateEvt:                    /*    Handle update events.    */
  423.                         BeginUpdate((WindowPtr) theEvent.message);
  424.                         EndUpdate((WindowPtr) theEvent.message);
  425.                     break;
  426.  
  427.                 case keyDown:                    /*    Handle key presses.        */
  428.                 case autoKey: 
  429.                     key = (char) (theEvent.message & charCodeMask);
  430.                     if (((theEvent.modifiers & cmdKey) != 0) && (theEvent.what == keyDown))
  431.                         DoMenuCommand(MenuKey(key));
  432.                     break;
  433.             }
  434.     }
  435.     while (!gQuitting);
  436. }
  437.  
  438.  
  439. /*------ MoveThePicts ----------------------------------------------------------------*/
  440. //    MoveThePicts moves the current pictures… somewhere randomly.  It
  441. //    first erases all the pictures in descending order.  Then it redraws
  442. //    them in new locations in ascending order. This way we don't wipe out
  443. //    any of the new pictures when the old ones are erased.
  444. /*----------------------------------------------------------------------------------------*/
  445.  
  446. void MoveThePicts(Rect *wBounds)
  447. {
  448.     int        newLeft, newTop, width, height, idx;
  449.     float    maxX, maxY;
  450.     Rect    picFrame, curPos;
  451.  
  452. /*    First erase all pictures in reverse order.  Also, calculate their
  453.     new locations and store those in their curPos fields.                */
  454.  
  455.     for (idx = gPICTRec.numPICTs -1; idx >= 0; idx--)
  456.     {
  457.         curPos = gPICTRec.curPos[idx];
  458.         EraseRect(&curPos);
  459.  
  460.         picFrame = (*gPICTRec.picture[idx])->picFrame;
  461.         width = picFrame.right -picFrame.left;
  462.         height = picFrame.bottom -picFrame.top;
  463.  
  464.  
  465. /*    To calculate new positions, we find the maximum position we can
  466.     have for the picture's top left corner.  Then, we find a random
  467.     point that's bounded by (0, 0) and that maximum.  Finally, we
  468.     set this picture's current position so that it has this point for
  469.     its top left corner.                                                */
  470.  
  471.         maxX = (wBounds->right - wBounds->left) -width;
  472.         maxY = (wBounds->bottom - wBounds->top) -height;
  473.         
  474.         newTop = (((float) Random() +32767)/65534.0) * maxX;
  475.         newLeft = (((float) Random() +32767)/65534.0) * maxY;
  476.     
  477.         curPos.top = newTop;
  478.         curPos.left = newLeft;
  479.         curPos.bottom = newTop +height;
  480.         curPos.right = newLeft +width;
  481.         gPICTRec.curPos[idx] = curPos;
  482.     }
  483.  
  484.  
  485. /*    Now draw all the pictures in their new positions.                    */
  486.  
  487.     for (idx = 0; idx < gPICTRec.numPICTs; idx++)
  488.         DrawPicture(gPICTRec.picture[idx], &gPICTRec.curPos[idx]);
  489. }
  490.  
  491.  
  492. /*------ MakeThePicts ----------------------------------------------------------------*/
  493. //    MakeThePicts creates the pictures that will be grouped.  These can be
  494. //    any QuickDraw pictures.  For this example, I use four pictures; one
  495. //    containing a square, one with a circle, one with a triangle and one
  496. //    with some text.  These are all stored in the global picture record.
  497.     
  498. //    This routine is only called once, to put some pictures into the works to
  499. //    start with.
  500. /*----------------------------------------------------------------------------------------*/
  501.  
  502. void MakeThePicts()
  503. {
  504.     RgnHandle    oldClip;
  505.     PolyHandle    trianglePoly;
  506.     int            fNum, vPos;
  507.  
  508. /*    Save the current clipping region so that we can restore it later.
  509.     Set our own clipping region, so that we know we have a valid one.
  510.     Also initialize the number of pictures in our global picture
  511.     structure to zero.                                                    */
  512.  
  513.     oldClip = NewRgn();
  514.     GetClip(oldClip);
  515.  
  516.     SetRect(&gPictsBounds, 0, 0, 150, 150);
  517.     ClipRect(&gPictsBounds);
  518.     
  519.     gPICTRec.numPICTs = 0;
  520.  
  521.  
  522. /*    Create a picture with a blue square in it.  We set the curPos
  523.     rectangle for all of these pictures to (0, 0, 0, 0) so that
  524.     we don't do any unnecessary erasing the first time they enter
  525.     MoveTheGroupies.                                                    */
  526.  
  527.     gPICTRec.picture[0] = OpenPicture(&gPictsBounds);
  528.     ForeColor(blueColor);
  529.     PaintRect(&gPictsBounds);
  530.     ClosePicture();
  531.     SetRect(&gPICTRec.curPos[0], 0, 0, 0, 0);
  532.     ++gPICTRec.numPICTs;
  533.  
  534.  
  535. /*    Create a picture with a red circle in it.                            */
  536.  
  537.     gPICTRec.picture[1] = OpenPicture(&gPictsBounds);
  538.     ForeColor(redColor);
  539.     PaintOval(&gPictsBounds);
  540.     ClosePicture();
  541.     SetRect(&gPICTRec.curPos[1], 0, 0, 0, 0);
  542.     ++gPICTRec.numPICTs;
  543.  
  544.  
  545. /*    Create a picture with a green triangle in it.    */
  546.  
  547.     gPICTRec.picture[2] = OpenPicture(&gPictsBounds);
  548.     ForeColor(greenColor);
  549.  
  550.     trianglePoly = OpenPoly();
  551.     MoveTo(gPictsBounds.left, gPictsBounds.bottom);
  552.     LineTo((gPictsBounds.right - gPictsBounds.left)/2, gPictsBounds.top);
  553.     LineTo(gPictsBounds.right, gPictsBounds.bottom);
  554.     LineTo(gPictsBounds.left, gPictsBounds.bottom);
  555.     ClosePoly();
  556.  
  557.     PaintPoly(trianglePoly);
  558.     KillPoly(trianglePoly);
  559.     ClosePicture();
  560.     SetRect(&gPICTRec.curPos[2], 0, 0, 0, 0);
  561.     ++gPICTRec.numPICTs;
  562.  
  563.  
  564. /*    Create a picture with some text in it.    */
  565.  
  566.     gPICTRec.picture[3] = OpenPicture(&gPictsBounds);
  567.     ForeColor(blackColor);
  568.  
  569.     GetFNum((ConstStr255Param) "\pTimes", (short*)&fNum);
  570.     TextFont(fNum);
  571.     TextSize(12);
  572.     TextFont(bold);
  573.     vPos = gPictsBounds.top +(gPictsBounds.bottom - gPictsBounds.top)/2;
  574.     MoveTo(gPictsBounds.left +10, vPos +10);
  575.     DrawString((ConstStr255Param) "\pCustom PicComments");
  576.     ClosePicture();
  577.     SetRect(&gPICTRec.curPos[3], 0, 0, 0, 0);
  578.     ++gPICTRec.numPICTs;
  579.  
  580.  
  581. /*    Restore the original clipping region.                                */
  582.  
  583.     SetClip(oldClip);
  584.     DisposeRgn(oldClip);
  585. }
  586.  
  587.  
  588. /*------ ShowThePicts ----------------------------------------------------------------*/
  589. //    ShowThePicts starts the show.
  590. //    First, we find the deepest display because the groupies are a colorful
  591. //    bunch.  Then we create a window and some pictures.  Finally, we jump into
  592. //    our main event loop.
  593. /*----------------------------------------------------------------------------------------*/
  594.  
  595. void ShowThePicts()
  596. {
  597.     Rect        maxRect, deepRect, wBounds;
  598.     GDHandle    deepGDH;
  599.  
  600. /*    Find the bounds of the deepest device.  We'll use this to determine
  601.     where to put our window.  Passing the maximum enclosing rectangle
  602.     to GetMaxDevice assures that we find the deepest device available.    */
  603.  
  604.     SetRect(&maxRect, -32767, -32767, 32767, 32767);
  605.     deepGDH = GetMaxDevice(&maxRect);
  606.     deepRect = (*deepGDH)->gdRect;
  607.  
  608.  
  609. /*    Create a window for our drawing, offset onto the deepest device.    */
  610.     
  611.     SetRect(&wBounds, 40, 40, 360, 340);
  612.     OffsetRect(&wBounds, wBounds.left +deepRect.left, wBounds.top +deepRect.top);
  613.  
  614.     gTheWindow = NewWindow(nil, &wBounds, (ConstStr255Param) "\pCustomPC/B", true, noGrowDocProc, (WindowPtr) -1, false, 1234);
  615.     SetPort(gTheWindow);
  616.  
  617.  
  618. /*    Create our pictures to group, then go into the work loop.  This
  619.     loop continually groups the pictures, draws the grouped picture
  620.     in different locations, ungroups the picture, draws the ungrouped
  621.     pictures in different locations and repeats until the user quits.    */
  622.  
  623.     MakeThePicts();
  624.     EventLoop();
  625. }
  626.  
  627.  
  628. /*------ CompositePictures ----------------------------------------------------------------*/
  629. //    CompositePictures groups all of the pictures in the global picture record
  630. //    into one "composite" picture.  It removes all the old pictures and
  631. //    stores the new one.
  632. /*----------------------------------------------------------------------------------------*/
  633.  
  634. /*    -------------------------------------
  635.     main.
  636.     -------------------------------------    */
  637.  
  638. void main(void)
  639. {    
  640.     unsigned long randSeed;
  641.     Handle        menuBar;
  642.  
  643. /*    Initialize the toolbox routines.                                    */
  644.  
  645.     InitGraf(&qd.thePort);
  646.     InitFonts();
  647.     InitWindows();
  648.     InitMenus();
  649.     InitDialogs(nil);
  650.     InitCursor();
  651.  
  652.  
  653. /*    Set up our menubar.                                                    */
  654.  
  655.     menuBar = GetNewMBar(rMenuBar);        /*    Read menus into menu bar    */
  656.     SetMenuBar(menuBar);                /*    and install them.            */
  657.     DisposeHandle(menuBar);
  658.     
  659.     AppendResMenu(GetMenuHandle(mApple), 'DRVR');
  660.     DrawMenuBar();
  661.  
  662.  
  663. /*    Initialize the random number seed for our hopping groupies and set
  664.     our quitting flag to false.  Call the routine that runs everything,
  665.     then, quit.                                                            */
  666.  
  667.     GetDateTime(&randSeed);
  668.     gQuitting = false;
  669.     ShowThePicts();
  670. }
  671.